
#include <BConstraint>
#include "member_BConstraint.h"
#include "member_BGroup.h"
#include "member_BNode.h"

using namespace BWE;

#define member					(*(member_BConstraint*)_ptr)
#define member_allocate()		_ptr = new member_BConstraint(this)
#define member_release()		delete (member_BConstraint*)_ptr

BConstraint::BConstraint()
{
	member_allocate();
}
BConstraint::BConstraint(const BString& name) : BObject(name)
{
	member_allocate();
}
BConstraint::BConstraint(BNode* nodeA, const BVector& pointA)
{
	member_allocate();
	if (nodeA)
	{
		member.nodeA = nodeA;
		node_member(nodeA)->constraintRefs.insert(this);
	}
	member.pointA = pointA;
}
BConstraint::BConstraint(BNode* nodeA, BNode* nodeB)
{
	member_allocate();
	if (nodeA)
	{
		member.nodeA = nodeA;
		node_member(nodeA)->constraintRefs.insert(this);
	}
	if (nodeB)
	{
		member.nodeB = nodeB;
		node_member(nodeB)->constraintRefs.insert(this);
	}
}
BConstraint::BConstraint(BNode* nodeA, const BVector& pointA, const BVector& solidPoint)
{
	member_allocate();
	if (nodeA)
	{
		member.nodeA = nodeA;
		node_member(nodeA)->constraintRefs.insert(this);
	}
	member.pointA = pointA;
	member.pointB = solidPoint;
}
BConstraint::BConstraint(BNode* nodeA, const BVector& pointA, BNode* nodeB, const BVector& pointB)
{
	member_allocate();
	if (nodeA)
	{
		member.nodeA = nodeA;
		node_member(nodeA)->constraintRefs.insert(this);
	}
	member.pointA = pointA;
	if (nodeB)
	{
		member.nodeB = nodeB;
		node_member(nodeB)->constraintRefs.insert(this);
	}
	member.pointB = pointB;
}
BConstraint::~BConstraint()
{
	if (BNode* node = member.nodeA)
		node_member(node)->constraintRefs.remove(this);
	if (BNode* node = member.nodeB)
		node_member(node)->constraintRefs.remove(this);
	member_release();
}

void BConstraint::setGroup(BGroup* group)
{
	if (group && member.group != group)
	{
		group->insert(this);
	}
}
BGroup* BConstraint::group() const
{
	return member.group;
}

void BConstraint::setNodeA(BNode* nodeA, const BVector& pointA)
{
	bool changed = false;
	if (member.nodeA != nodeA)
	{
		if (BNode* node = member.nodeA)
			node_member(node)->constraintRefs.remove(this);
		member.nodeA = nodeA;
		if (BNode* node = member.nodeA)
			node_member(node)->constraintRefs.insert(this);
		changed = true;
	}
	if (member.pointA != pointA)
	{
		member.pointA = pointA;
		changed = true;
	}
	if (changed)
	{
		this->emit(Signal_Changed);
	}
}
void BConstraint::setNodeA(BNode* nodeA)
{
	if (member.nodeA != nodeA)
	{
		if (BNode* node = member.nodeA)
			node_member(node)->constraintRefs.remove(this);
		member.nodeA = nodeA;
		if (BNode* node = member.nodeA)
			node_member(node)->constraintRefs.insert(this);
		this->emit(Signal_Changed);
	}
}
BNode* BConstraint::nodeA() const
{
	return member.nodeA;
}

void BConstraint::setNodeB(BNode* nodeB, const BVector& pointB)
{
	bool changed = false;
	if (member.nodeB != nodeB)
	{
		if (BNode* node = member.nodeB)
			node_member(node)->constraintRefs.remove(this);
		member.nodeB = nodeB;
		if (BNode* node = member.nodeB)
			node_member(node)->constraintRefs.insert(this);
		changed = true;
	}
	if (member.pointB != pointB)
	{
		member.pointB = pointB;
		changed = true;
	}
	if (changed)
	{
		this->emit(Signal_Changed);
	}
}
void BConstraint::setNodeB(BNode* nodeB)
{
	if (member.nodeB != nodeB)
	{
		if (BNode* node = member.nodeB)
			node_member(node)->constraintRefs.remove(this);
		member.nodeB = nodeB;
		if (BNode* node = member.nodeB)
			node_member(node)->constraintRefs.insert(this);
		this->emit(Signal_Changed);
	}
}
BNode* BConstraint::nodeB() const
{
	return member.nodeB;
}

void BConstraint::setPointA(const BVector& pointA)
{
	if (member.pointA != pointA)
	{
		member.pointA = pointA;
		this->emit(Signal_Changed);
	}
}
const BVector& BConstraint::pointA() const
{
	return member.pointA;
}

void BConstraint::setPointB(const BVector& pointB)
{
	if (member.pointB != pointB)
	{
		member.pointB = pointB;
		this->emit(Signal_Changed);
	}
}
const BVector& BConstraint::pointB() const
{
	return member.pointB;
}

void BConstraint::setInnerCollible(bool innerCollible)
{
	if (member.innerCollible != innerCollible)
	{
		member.innerCollible = innerCollible;
		this->emit(Signal_Changed);
	}
}
bool BConstraint::innerCollible() const
{
	return member.innerCollible;
}

void BConstraint::setBreakImpulse(BReal breakImpulse)
{
	if (member.breakImpulse != breakImpulse)
	{
		member.breakImpulse = breakImpulse;
		this->emit(Signal_Changed);
	}
}
BReal BConstraint::breakImpulse() const
{
	return member.breakImpulse;
}

bool BConstraint::contain(const BNode* node) const
{
	return member.nodeA == node || member.nodeB == node;
}

void BConstraint::clear()
{
	bool changed = false;
	if (member.nodeA)
	{
		member.nodeA = 0;
		member.pointA.reset();
		changed = true;
	}
	if (member.nodeB)
	{
		member.nodeB = 0;
		member.pointB.reset();
		changed = true;
	}
	if (changed)
	{
		this->emit(Signal_Changed);
	}
}
void BConstraint::solve()
{

}
